//
//  ModelParser.m
//  ModelParser
//
//  Created by JackAndney on 2018/1/2.
//  Copyright © 2018年 Andney. All rights reserved.
//

#import "ModelParser.h"

//#define PROPERTY_KEY_FOR_ID  @"modelId"
#define PROPERTY_KEY_FOR_ID  @"Id"


@interface ModelParser ()
@property (nonatomic, copy) NSArray *tmpAllKeys;
@end


@implementation ModelParser

- (instancetype)init {
    self = [super init];
    if (self) {
        self.sortedByOrderInString = YES;
        self.addComment            = YES;
        self.addImplementationPart = YES;
    }
    return self;
}


- (BOOL)startParse {
    
    if (self.jsonDict == nil || self.jsonDict.count == 0) {
        if (self.jsonString.length < 2) {
            [self handleErrorMessage:@"输入的json字符串为空 或 字典为空！"];
            return NO;
            
        }else {
            self.jsonString = [self.jsonString stringByReplacingOccurrencesOfString:@"\\s+" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, self.jsonString.length)];
            
            NSData *jsonData = [self.jsonString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
            
            NSError *error = nil;
            id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves|NSJSONReadingMutableContainers error:&error];
            if (error) {
                [self handleErrorMessage:[NSString stringWithFormat:@"JSON解析出错：%@", error.localizedDescription]];
                return NO;
            }
            
            if ([jsonObj isKindOfClass:[NSArray class]]) {
                if ([jsonObj count] > 0 && [jsonObj[0] isKindOfClass:[NSDictionary class]] && [jsonObj[0] count] > 0) {
                    
                }else {
                    [self handleErrorMessage:@"下一级JSON对象为空！"];
                    return NO;
                }
            }
            
            self.jsonDict = jsonObj;
        }
    }
    
    if (self.className.length < 1) {
        [self handleErrorMessage:@"类名为空！"];
        return NO;
    }
    
    
    [self m_startParser];
    
    return YES;
}




- (void)m_startParser {
    if (self.jsonDict.count < 1 || self.jsonDict == nil) {
        [self handleErrorMessage:@"JSON对象为空！"];
        return;
    }
    
    if (![self.jsonDict isKindOfClass:[NSDictionary class]]) {
        [self handleErrorMessage:@"JSON对象不是字典！"];
        return;
    }
    
    // key值排序
    if (self.tmpAllKeys == nil) {
        NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:[self.jsonDict allKeys]];
        
        if (self.sortedByOrderInString) {
            
            __weak typeof(self) weakSelf = self;
            self.tmpAllKeys = [tmpArray sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
                NSString *key1 = [NSString stringWithFormat:@"\"%@\":", obj1];
                NSString *key2 = [NSString stringWithFormat:@"\"%@\":", obj2];
                
                NSInteger location1 = [weakSelf.jsonString rangeOfString:key1 options:NSRegularExpressionSearch range:NSMakeRange(0, weakSelf.jsonString.length)].location;
                NSInteger location2 = [weakSelf.jsonString rangeOfString:key2 options:NSRegularExpressionSearch range:NSMakeRange(0, weakSelf.jsonString.length)].location;
                
                if (location1 != NSNotFound && location2 != NSNotFound) {
                    if (location1 > location2) {
                        return NSOrderedDescending;
                    }else if (location1 < location2) {
                        return NSOrderedAscending;
                    }
                }
                return NSOrderedSame;
            }];
            
        }else {
            self.tmpAllKeys = [self.jsonDict.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
                return [obj1 compare:obj2];
            }];
        }
    }
    
    NSMutableString *results = [NSMutableString stringWithString:@""];
    
    [results appendFormat:@"/*************************************  %@ ****************************************/", self.className];
    
    NSString *hString = [self parseForH];
    NSString *mString = [self parseForM];
    
    [results appendFormat:@"\n\n%@\n\n\n// ——————————————————————————————————————\n\n%@", hString, mString];
    
    [self handleSuccessResult:results];
    
    
    for (NSString *key in self.tmpAllKeys) {
        id value = [self.jsonDict valueForKey:key];
        
        if (([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) && [value count] > 0) {
            NSString *subclassName = ClassNameFromPropertyName(key);
            
            ModelParser *anotherParser = [ModelParser new];
            anotherParser.jsonString = self.jsonString;
            
            anotherParser.className             = subclassName;
            anotherParser.replaceKeyForId       = self.replaceKeyForId;
            anotherParser.sortedByOrderInString = self.sortedByOrderInString;
            anotherParser.addComment            = self.addComment;
            anotherParser.addImplementationPart = self.addImplementationPart;
            
            anotherParser.delegate        = self.delegate;
            anotherParser.completionBlock = self.completionBlock;
            
            if ([value isKindOfClass:[NSDictionary class]]) {
                anotherParser.jsonDict = value;
            }else {
                // 属性值为数组
                id firstValue = [value firstObject];
                if ([firstValue isKindOfClass:[NSDictionary class]]) {
                    anotherParser.jsonDict = firstValue;
                }else if ([firstValue isKindOfClass:[NSArray class]]) {
                    [self handleErrorMessage:@"暂不支持数组对象里仍是数组对象的解析！"];
                    continue;
                }else {
                    continue;
                }
            }
            
            [anotherParser startParse];
        }
    }
}




#pragma mark - 解析类



- (NSString *)parseForH {
    
    NSMutableString *resultString = [NSMutableString stringWithString:@""];
    
    [resultString appendFormat:@"\n\n@interface %@ : NSObject\n\n", self.className];
    
    for (NSString *key in self.tmpAllKeys) {
        NSString *defineString = [self propertyDefineForKey:key andValue:self.jsonDict[key]];
        if (self.addComment) {
            [resultString appendFormat:@"/** <#%@描述#> */\n%@", key, defineString];
        }else {
            [resultString appendString:defineString];
        }
    }
    
    if (self.addImplementationPart) {
        [resultString appendString:@"\n\n- (instancetype)initWithAttributes:(NSDictionary *)dict;\n"];
        [resultString appendFormat:@"+ (NSArray<%@ *> *)instanceArrayFromDictArray:(NSArray<NSDictionary *> *)dicArray;\n", self.className];
    }
    
    [resultString appendString:@"\n@end"];
    
    return resultString;
}

- (NSString *)parseForM {
    NSMutableString *resultString = [NSMutableString stringWithString:@""];
    
    [resultString appendFormat:@"\n\n@implementation %@\n\n", self.className];
    
    if (self.addImplementationPart) {
        [resultString appendString:@"- (instancetype)initWithAttributes:(NSDictionary *)dict {\n\
		if (self = [super init]) {\n\
			if (!dict || !([dict isKindOfClass:[NSDictionary class]] && dict.count > 0)) {\n\
				return nil;\n\
			}\n\n"];
		
        for (NSString *key in self.tmpAllKeys) {
            [resultString appendFormat:@"\t\t%@", [self propertyAssignmentForKey:key andValue:self.jsonDict[key]]];
        }
		
		[resultString appendString:@"\t}\n\treturn self;\n}\n\n"];
		
		[resultString appendFormat:@"\n+ (NSArray<%@ *> *)instanceArrayFromDictArray:(NSArray<NSDictionary *> *)dicArray {\n\
			if (!dicArray || ![dicArray isKindOfClass:[NSArray class]]) {\n\
				return @[];\n\
			}\n\n\
			NSMutableArray *instanceArray = [NSMutableArray array];\n\
			for (NSDictionary *instanceDic in dicArray) {\n\
				%@ *model = [[self.class alloc] initWithAttributes:instanceDic];\n\
				if (model) {\n\
					[instanceArray addObject:model];\n\
				}\n\
			}\n\
			return [NSArray arrayWithArray:instanceArray];\n\
		}\n" , self.className, self.className];
        
        [resultString appendString:@"\n\n@end"];
    }else {
        [resultString appendString:@"@end"];
    }

    [resultString appendString:@"\n\n\n\n"];
    
    
    return resultString;
}


/**
 *  属性声明
 *
 *  @param key   属性名
 *  @param value 属性值
 */
- (NSString *)propertyDefineForKey:(NSString *)key andValue:(id)value {
    NSMutableString *resultString = [NSMutableString string];

    
    if ([key isEqualToString:@"id"]) {
        NSString *replaceKey = self.replaceKeyForId.length>0 ? [self.replaceKeyForId copy] : PROPERTY_KEY_FOR_ID;
        
        if ([value isKindOfClass:[NSNumber class]]) {
            [resultString appendFormat:@"@property (nonatomic, assign) NSInteger %@;\n", replaceKey];
        }else {
            [resultString appendFormat:@"@property (nonatomic, copy) NSString *%@;\n", replaceKey];
        }
        
        return resultString;
    }
    
    
    if ([value isKindOfClass:[@(YES) class]]) {
        [resultString appendFormat:@"@property (nonatomic, assign) BOOL %@;\n", key];
    }else if ([value isKindOfClass:[NSNumber class]]) {
        if ([[value stringValue] rangeOfString:@"."].location != NSNotFound) {
            [resultString appendFormat:@"@property (nonatomic, assign) CGFloat %@;\n", key];
        }else {
            if ([value longValue] < 2147483648) {
                [resultString appendFormat:@"@property (nonatomic, assign) NSInteger %@;\n", key];
            }else {
                [resultString appendFormat:@"@property (nonatomic, assign) long long %@;\n", key];
            }
        }
    }else if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNull class]]) {
        [resultString appendFormat:@"@property (nonatomic, copy) NSString *%@;\n", key];
    }else if ([value isKindOfClass:[NSDictionary class]]) {
        // 字典
        [resultString appendFormat:@"@property (nonatomic, strong) %@ *%@;\n", ClassNameFromPropertyName(key), key];
    }else if ([value isKindOfClass:[NSArray class]]) {
        NSArray *array = (NSArray *)value;
        if (array.count && [[array firstObject] isKindOfClass:[NSDictionary class]]) {
            [resultString appendFormat:@"@property (nonatomic, strong) NSArray<%@ *> *%@List;\n", ClassNameFromPropertyName(key), key];
        }else {
            [resultString appendFormat:@"@property (nonatomic, strong) NSArray *%@s;\n", key];
        }
    }
    
    return resultString;
}

/**
 *  属性赋值
 *
 *  @param key   属性名
 *  @param value 属性值
 */
- (NSString *)propertyAssignmentForKey:(NSString *)key andValue:(id)value {
    NSMutableString *resultString = [NSMutableString string];
    
    if ([key isEqualToString:@"id"]) {
        NSString *replaceKey = self.replaceKeyForId.length>0 ? [self.replaceKeyForId copy] : PROPERTY_KEY_FOR_ID;
        
        if ([value isKindOfClass:[NSNumber class]]) {
            [resultString appendFormat:@"self.%@ = [dict safeIntegerForKey:@\"%@\"];\n", replaceKey, key];
        }else {
            [resultString appendFormat:@"self.%@ = [dict safeStringForKey:@\"%@\"];\n", replaceKey, key];
        }
        
        return resultString;
    }
    
    
    if ([value isKindOfClass:[@(YES) class]]) {
        [resultString appendFormat:@"self.%@ = [dict safeBoolForKey:@\"%@\"];\n", key, key];
    }else if ([value isKindOfClass:[NSNumber class]]) {
        if ([[value stringValue] rangeOfString:@"."].location != NSNotFound) {
            [resultString appendFormat:@"self.%@ = [dict safeFloatForKey:@\"%@\"];\n", key, key];
        }else {
            if ([value longValue] < 2147483648) {
                [resultString appendFormat:@"self.%@ = [dict safeIntegerForKey:@\"%@\"];\n", key, key];
            }else {
                [resultString appendFormat:@"self.%@ = [dict safeIntegerForKey:@\"%@\"];\n", key, key];
            }
        }
    }else if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNull class]]) {
        [resultString appendFormat:@"self.%@ = [dict safeStringForKey:@\"%@\"];\n", key, key];
    }else if ([value isKindOfClass:[NSDictionary class]]) {
        [resultString appendFormat:@"self.%@ = [[%@ alloc] initWithAttributes:dict[@\"%@\"]];\n", key, ClassNameFromPropertyName(key), key];
    }else if ([value isKindOfClass:[NSArray class]]) {
        
        NSArray *array = (NSArray *)value;
        if (array.count && [[array firstObject] isKindOfClass:[NSDictionary class]]) {
            [resultString appendFormat:@"self.%@List = [%@ instanceArrayFromDictArray:dict[@\"%@\"]];\n", key, ClassNameFromPropertyName(key), key];
        }else {
            [resultString appendFormat:@"self.%@s = [dict safeArrayForKey:@\"%@\"];\n", key, key];
        }
    }
    
    return resultString;
}


/**
 *  根据属性名获取类名
 *
 *  @param propertyName 属性名
 *
 *  @return 子类的类名
 */
NSString *ClassNameFromPropertyName(NSString *propertyName) {
    if (propertyName.length > 0) {
        NSString *className = [NSString stringWithFormat:@"%@%@",[[propertyName substringToIndex:1] uppercaseString], [propertyName substringFromIndex:1]];
        if ([className hasSuffix:@"s"]) {
            return [NSString stringWithFormat:@"%@Model", [className substringToIndex:className.length-1]];
        }else {
            return [NSString stringWithFormat:@"%@Model", className];
        }
    }
    return @"SubclassName";
}





#pragma mark -  回调处理

- (void)handleErrorMessage:(NSString *)error {
    if (self.delegate && [self.delegate respondsToSelector:@selector(parser:didFailWithError:)]) {
        [self.delegate parser:self didFailWithError:error];
    }else {
        if (self.completionBlock) {
            self.completionBlock(NO, error);
        }
    }
}


- (void)handleSuccessResult:(NSString *)result {
    if (self.delegate && [self.delegate respondsToSelector:@selector(parser:didCompleteWithResult:)]) {
        [self.delegate parser:self didCompleteWithResult:result];
    }else {
        if (self.completionBlock) {
            self.completionBlock(YES, result);
        }
    }
}







#pragma mark -  



NSString *StringRemoveUnicode(NSString *string) {
    if ([string isKindOfClass:[NSString class]] && string.length > 0) {
        NSMutableString *convertedString = [string mutableCopy];
        [convertedString replaceOccurrencesOfString:@"\\U" withString:@"\\u" options:0 range:NSMakeRange(0, convertedString.length)];
        CFStringRef transform = CFSTR("Any-Hex/Java");
        CFStringTransform((__bridge CFMutableStringRef)convertedString, NULL, transform, YES);
        return convertedString;
    }
    return @"";
}

void MYLOG(id obj) {
    NSLog(@"输出: %@", StringRemoveUnicode([obj description]));
}


@end
